#include "nvs.h"

#define NVS_Key_STA_SSID "S_ID"
#define NVS_Key_STA_Password "S_Pw"
#define NVS_Key_firmware_version "S_Fw"
#define NVS_ca_cert "S_ca"
#define NVS_private_1 "S_pr1"
#define NVS_private_2 "S_pr2"
#define Nvs_Unit "NUnit"


static const char *TAG_NVS = "NVS";
static const char *clear_inform = "null";
extern volatile char *g_wifi_ssid;
extern volatile char *g_wifi_password;
esp_err_t NVS_Read_WiFi(void);
static char nvs_ssid[100];
static char nvs_password[100];


void NVS_Write_Unit(void)
{
    // Initialize NVS
    esp_err_t err = nvs_flash_init();
    if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND)
    {
        // NVS partition was truncated and needs to be erased
        // Retry nvs_flash_init
        ESP_ERROR_CHECK(nvs_flash_erase());
        err = nvs_flash_init();
    }
    ESP_ERROR_CHECK(err);

    nvs_handle_t my_handle;
    err = nvs_open("storage", NVS_READWRITE, &my_handle);
    if (err != ESP_OK)
    {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    }
    else
    {
        // Write
        err = nvs_set_u32(my_handle, Nvs_Unit, UI_System.Grill_Unit);

        // Commit written value.
        // After setting any values, nvs_commit() must be called to ensure changes are written
        // to flash storage. Implementations may write to storage at other times,
        // but this is not guaranteed.
        err = nvs_commit(my_handle);
        // Close
        nvs_close(my_handle);
    }
}
//nvs记录wifi信息
void NVS_Write_WiFi(void *pvParameters)
{
    nvs_handle_t my_handle;
    esp_err_t err;
    while (1)
    {
        if (wireless_state.nvs_save_inform == get_inform) //判读记录wifi信息标志
        {
            ESP_LOGI(TAG_NVS, "校验 存储在Flash的 SSID Password");
            if((strcmp((char*)nvs_ssid,g_wifi_ssid) != 0) || (strcmp((char*)nvs_password,g_wifi_password) != 0))
            {
                err = nvs_open("storage", NVS_READWRITE, &my_handle); //开启NVS
                if (err != ESP_OK)
                {
                    printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
                }
                ESP_LOGI(TAG_NVS, "Write SSID Password to NVS");
                // Write

                ESP_LOGI(TAG_NVS, "nvs write ssid :%s", g_wifi_ssid);
                ESP_LOGI(TAG_NVS, "nvs write password :%s", g_wifi_password);
                nvs_set_str(my_handle, NVS_Key_STA_SSID, g_wifi_ssid);         //写入ssid
                nvs_set_str(my_handle, NVS_Key_STA_Password, g_wifi_password); //写入password

                // Commit written value.
                // After setting any values, nvs_commit() must be called to ensure changes are written
                // to flash storage. Implementations may write to storage at other times,
                // but this is not guaranteed.
                ESP_LOGI(TAG_NVS, "Committing updates in NVS ... ");
                err = nvs_commit(my_handle); //提交修改
                if (err != ESP_OK)
                {
                    printf("Error Commit!!!");
                }
                nvs_close(my_handle); //关闭nvs
                ESP_LOGI(TAG_NVS, "load the wifi ssid and password");
            }
            else
            {
                ESP_LOGI(TAG_NVS, "校验Flash 已存在SSID: %s Password: %s, 取消Flash写操作",g_wifi_ssid,g_wifi_password);
            }
            // ESP_ERROR_CHECK(NVS_Read_WiFi());                               //读取wifi信息
            wireless_state.nvs_save_inform = no_inform; //复位wifi信息标志位
        }
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

// 读取wifi信息
esp_err_t NVS_Read_WiFi(void)
{
    nvs_handle_t my_handle;
    uint8_t temp = 0;
    g_wifi_ssid = NVS_Key_STA_SSID;
    g_wifi_password = NVS_Key_STA_Password;
    uint32_t unit;

    ESP_LOGI(TAG_NVS, "start reading wifi inform...");

    esp_err_t err = nvs_open("storage", NVS_READONLY, &my_handle); //开启NVS
    if (err != ESP_OK)
    {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    }
    temp = 100;
    nvs_get_str(my_handle, NVS_Key_STA_SSID, nvs_ssid, &temp);         //读取SSID
    temp = 100;                                                        //必须重置
    nvs_get_str(my_handle, NVS_Key_STA_Password, nvs_password, &temp); //读取PASSWORD
    nvs_get_u32(my_handle,Nvs_Unit,&unit);
    if((unit == Unit_F) || (unit == Unit_C))
    {
        UI_System.Grill_Unit = unit;
    }
    nvs_close(my_handle);                                              //关闭NVS
    if(UI_System.Grill_Unit == Unit_F) UI_Default_F();
    else UI_Default_C();

    if (strlen(nvs_ssid) == 0)
    {
        ESP_LOGI(TAG_NVS, "no imform");
        g_wifi_ssid = TAG_NVS;
    }
    else
    {
        ESP_LOGI(TAG_NVS, "get useful ssid");
        g_wifi_ssid = &nvs_ssid;
        g_wifi_password = &nvs_password;
        ESP_LOGI(TAG_NVS, "Read NVS SSID: %s", g_wifi_ssid);
        ESP_LOGI(TAG_NVS, "Read NVS Password: %s", g_wifi_password);
        WIFI_Connect_Trigger();
    }

    return ESP_OK;
}

//nvs记录证书信息
void NVS_Write_cert(void)
{
    extern volatile unsigned char ca_cert[1300];
    extern volatile unsigned char private_cert[1700];

    unsigned char temp_private_cert_1[1010];
    unsigned char temp_private_cert_2[1010];
    char *aws_ca_cert;
    char *aws_private_cert_1;
    char *aws_private_cert_2;
    aws_ca_cert = &ca_cert;
    aws_private_cert_1 = &temp_private_cert_1;
    aws_private_cert_2 = &temp_private_cert_2;
    nvs_handle_t my_handle;
    esp_err_t err;

    for (int i = 0; i < 990; i++)
    {
        temp_private_cert_1[i] = private_cert[i];
    }
    ESP_LOGI(TAG_NVS, "private cert part 1 is :%s", temp_private_cert_1);
    for (int i = 0; i < 1000; i++)
    {
        temp_private_cert_2[i] = private_cert[i + 980];
    }
    ESP_LOGI(TAG_NVS, "private cert part 2 is :%s", temp_private_cert_2);

    err = nvs_open("storage", NVS_READWRITE, &my_handle); //开启NVS
    if (err != ESP_OK)
    {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    }
    ESP_LOGI(TAG_NVS, "Write cert to NVS");
    // Write

    // ESP_LOGI(TAG_NVS, "nvs write ca cert :%s", aws_ca_cert);
    // ESP_LOGI(TAG_NVS, "nvs write private cert :%s", aws_private_cert);
    nvs_set_str(my_handle, NVS_ca_cert, aws_ca_cert);          //写入ca cert
    nvs_set_str(my_handle, NVS_private_1, aws_private_cert_1); //写入private cert 第一部分
    nvs_set_str(my_handle, NVS_private_2, aws_private_cert_2); //写入private cert 第二部分

    // Commit written value.
    // After setting any values, nvs_commit() must be called to ensure changes are written
    // to flash storage. Implementations may write to storage at other times,
    // but this is not guaranteed.
    ESP_LOGI(TAG_NVS, "Committing updates in NVS ... ");
    err = nvs_commit(my_handle); //提交修改
    if (err != ESP_OK)
    {
        printf("Error Commit!!!");
    }
    nvs_close(my_handle); //关闭nvs
    ESP_LOGI(TAG_NVS, "confirm the aws cert");
    ESP_ERROR_CHECK(NVS_Read_cert()); //读取证书
}

// 读取证书信息
esp_err_t NVS_Read_cert(void)
{
    extern volatile unsigned char ca_cert[1300];
    extern volatile unsigned char private_cert[1700];

    nvs_handle_t my_handle;
    uint8_t temp = 0;

    static char test_ca_cert[1300];
    static char test_private[1700];

    static char test_private_1[1100];
    static char test_private_2[1100];

    ESP_LOGI(TAG_NVS, "start reading cert inform...");

    esp_err_t err = nvs_open("storage", NVS_READONLY, &my_handle); //开启NVS
    if (err != ESP_OK)
    {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
    }
    temp = 1300;
    nvs_get_str(my_handle, NVS_ca_cert, ca_cert, &temp);          //读取CA证书
    temp = 1000;                                                  //必须重置
    nvs_get_str(my_handle, NVS_private_1, test_private_1, &temp); //读取private证书 1
    temp = 1000;                                                  //必须重置
    nvs_get_str(my_handle, NVS_private_2, test_private_2, &temp); //读取private证书 2
    nvs_close(my_handle);                                         //关闭NVS

    for (int i = 0; i < 1700; i++)
    {
        if (i < 980)
        {
            private_cert[i] = test_private_1[i];
        }
        else
        {
            private_cert[i] = test_private_2[i - 980];
        }
    }
    if ((strlen(ca_cert) != 0) && (strlen(private_cert) != 0))
    {
        ESP_LOGI(TAG_NVS, "NVS have cert already");
        wireless_state.aws_cert = get_inform;
        ESP_LOGI(TAG_NVS, "nvs read ca is %s", ca_cert);
        // ESP_LOGI(TAG_NVS, "nvs read private part 1 is %s", test_private_1);
        // ESP_LOGI(TAG_NVS, "nvs read private part 2 is %s", test_private_2);
        ESP_LOGI(TAG_NVS, "nvs read private part  is %s", private_cert);
    }
    return ESP_OK;
}

//清除wifi信息
void NVS_Clear_WiFi(void *pvParameters)
{
    nvs_handle_t my_handle;
    esp_err_t err;
    while (1)
    {
        if (wireless_state.nvs_clear_inform == get_inform) //判读记录wifi信息标志
        {
            err = nvs_open("storage", NVS_READWRITE, &my_handle); //开启NVS
            if (err != ESP_OK)
            {
                printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
            }
            ESP_LOGI(TAG_NVS, "clear SSID Password to NVS");
            // Write

            ESP_LOGI(TAG_NVS, "nvs clear ssid :%s", clear_inform);
            ESP_LOGI(TAG_NVS, "nvs clear password :%s", clear_inform);
            nvs_set_str(my_handle, NVS_Key_STA_SSID, clear_inform);     //清除ssid
            nvs_set_str(my_handle, NVS_Key_STA_Password, clear_inform); //清除password

            // Commit written value.
            // After setting any values, nvs_commit() must be called to ensure changes are written
            // to flash storage. Implementations may write to storage at other times,
            // but this is not guaranteed.
            ESP_LOGI(TAG_NVS, "Committing updates in NVS ... ");
            err = nvs_commit(my_handle); //提交修改
            if (err != ESP_OK)
            {
                printf("Error Commit!!!");
            }
            nvs_close(my_handle); //关闭nvs
            ESP_LOGI(TAG_NVS, "clear the wifi ssid and password");
            ESP_ERROR_CHECK(NVS_Read_WiFi());            //读取wifi信息
            wireless_state.nvs_clear_inform = no_inform; //复位wifi信息清除标志位
        }
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

esp_err_t NVS_wifi_inform(void)
{
    ESP_ERROR_CHECK(NVS_Read_WiFi());                                   //读取wifi信息
    xTaskCreate(NVS_Write_WiFi, "NVS_Write_WiFi", 2048, NULL, 5, NULL); //写入wifi信息
    xTaskCreate(NVS_Clear_WiFi, "NVS_Clear_WiFi", 2048, NULL, 5, NULL); //清除wifi信息
    return ESP_OK;
}